package interview.a1b2c3;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;

/**
 * @author: 李德才
 * @description:
 * @create: 2020-12-19 11:53
 **/


/**
 * 两个线程分别输出 A-Z 和 1-26 ，
 * 要求两个线程交替输出
 * 即：A1B2C3D4
 */
public class Test_03_BlockingQueue {
    public static final String[] LETTER_ARRAY = new String[]{"A", "B", "C", "D", "E", "F"};
    public static final String[] NUMBER_ARRAY = new String[]{"1", "2", "3", "4", "5", "6"};
    static Thread thread_1 = null, thread_2 = null;
    private static final String STR = "A";
    /**
     * ******** 指定容量，满了程序就阻塞 **********
     * ArrayBlockingQueue是一个阻塞队列，底层使用数组结构实现，按照先进先出（FIFO）的原则对元素进行排序。
     * ArrayBlockingQueue是一个线程安全的集合，通过ReentrantLock锁来实现，在并发情况下可以保证数据的一致性。
     * 此外，ArrayBlockingQueue的容量是有限的，数组的大小在初始化时就固定了，不会随着队列元素的增加而出现扩容的情况，
     * 也就是说ArrayBlockingQueue是一个“有界缓存区”
     */

    /**
     * 这里设置两个阻塞队列的容量为1 ，最开始是没有数据的
     */
    private static final BlockingQueue<String> blockingQueue_1 = new ArrayBlockingQueue<>(1);
    private static final BlockingQueue<String> blockingQueue_2 = new ArrayBlockingQueue<>(1);


    public static void main(String[] args) {

        /**
         * 两个阻塞队列 最开始是没有数据的
         */
        /**
         *  注意：blockingQueue.take() 的意思是 获取和删除这个队列的头，如果需要等待，直到一个元素可用
         *  所以执行完 blockingQueue.take() 之后对应的队列中就不存在数据了
         */
        thread_1 = new Thread(() -> {
            try {
                for (String str : LETTER_ARRAY) {
//                   1、 先输出一个字母
                    System.err.println(str);
//                   2、 在 blockingQueue_1 中存入数据，这时候 blockingQueue_1 的监听就可以生效了
                    blockingQueue_1.put(STR);
//                    6、 blockingQueue_2 的监听生效，继续执行
                    blockingQueue_2.take();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread_2 = new Thread(() -> {
            try {
                for (String str : NUMBER_ARRAY) {
//                    3、blockingQueue_1 的监听生效，继续执行
                    blockingQueue_1.take();
//                    4、输出一个数字
                    System.err.println(str);
//                    5、blockingQueue_2 中存入数据，这时候 blockingQueue_2 的监听就可以生效了
                    blockingQueue_2.put(STR);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });


        /**
         * 其实就是用 ArrayBlockingQueue 是阻塞队列的特性，加上指定容量为 1 ，来作为一个特殊的 “锁”
         */

        thread_1.start();
        thread_2.start();
    }
}
